/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package Wires.impl;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.util.EObjectContainmentEList;
import org.eclipse.emf.ecore.util.InternalEList;
import org.eclipse.m2m.atl.engine.AtlCompiler;
import org.eclipse.m2m.atl.engine.vm.nativelib.ASMModel;

import Wires.DecisionNode;
import Wires.InputActualParameter;
import Wires.InputFormalParameter;
import Wires.LibraryRef;
import Wires.OutputActualParameter;
import Wires.OutputFormalParameter;
import Wires.Transformation;
import Wires.TransformationType;
import Wires.WiresPackage;
import Wires.exep.LibraryNotFoundException;
import Wires.exep.ResourceNotFoundException;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Transformation</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link Wires.impl.TransformationImpl#getInParams <em>In Params</em>}</li>
 *   <li>{@link Wires.impl.TransformationImpl#getOutParams <em>Out Params</em>}</li>
 *   <li>{@link Wires.impl.TransformationImpl#getControlNode <em>Control Node</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public abstract class TransformationImpl extends TypedElementImpl implements Transformation {
	/***************************************************/
	/***************** Modifications *******************/
	
	private Boolean active = true;	
	
	public void setActive(Boolean active) {
		this.active = active;
	}

	public Boolean getActive() {
		return active;
	}
		
	
	public Map<String, Object> getInputsMap(){
		Map<String, Object> models = new HashMap<String, Object>();
		List<InputActualParameter> inparam = this.getInParams();
		for (InputActualParameter parameter : inparam){
			//Put metamodel and model
			ASMModel metamodel = ((InputActualParameterImpl)parameter).getMetamodel();
			String metamodelName = ((InputFormalParameter)parameter.getType()).getTypeName();
			if (!models.keySet().contains(metamodelName)){
				models.put(metamodelName, metamodel);
			}			
			ASMModel model;						
			model = ((InputActualParameterImpl)parameter).getModel();						
			String modelName = parameter.getType().getName();
			models.put(modelName, model);																				
		}
		return models;
	}
	
	public void addOutputModels(Map<String, Object> models){
		for (OutputActualParameter parameter : this.getOutParams()){	
			//Load and put the output parameter Metamodel
			((OutputActualParameterImpl)parameter).loadMetamodel();
			ASMModel metamodel = ((OutputActualParameterImpl)parameter).getMetamodel();
			String metamodelName = ((OutputFormalParameter)parameter.getType()).getTypeName();
			if (!models.keySet().contains(metamodelName)){
				models.put(metamodelName, metamodel);
			}			
			//Create and set the output Model								
			((OutputActualParameterImpl)parameter).newModel();
			ASMModel model = ((OutputActualParameterImpl)parameter).getModel();
			String modelName = parameter.getType().getName();
			models.put(modelName, model);
		}
	}
	
	public Map<String,URL> getLibMap() throws IOException{
		Map<String, URL> libMap = new HashMap<String, URL>();
		for (LibraryRef lib : ((TransformationType)this.getType()).getLibraries()){
			this.addLibrary(lib, libMap);			
		}
		return libMap;
	}
	
	private void addLibrary(LibraryRef lib, Map<String,URL> libMap) throws IOException{
		if (lib.getLibrary() == null)
			throw new LibraryNotFoundException(lib);
		
		String compiledPath = "";
		try {
			compiledPath = this.compileAtl(lib.getLibrary().getPath());
		} catch (Exception e) {
			throw new ResourceNotFoundException(lib.getLibrary());
		}
		File f = new File(compiledPath);
		URL url = f.toURI().toURL();
		libMap.put(lib.getName(), url);
		for (LibraryRef libRef : lib.getLibrary().getLibraries()){
			this.addLibrary(libRef, libMap);
		}
	}
	
	//Compile the sourcePath file and return the path of the compiled file
	public String compileAtl(String sourcePath) throws MalformedURLException, IOException{
		String transformationPath = sourcePath;
		int dotPos = transformationPath.lastIndexOf(".");
        String extension = transformationPath.substring(dotPos);
        if (extension.equals(new String(".atl"))){
        	String pathAsm = transformationPath.substring(0, dotPos) + ".asm";
        	File fileAsm = new File(pathAsm);
        	String absPath = fileAsm.getAbsolutePath();
        	File fileAtl = new File(transformationPath);
        	String absAtlPath = fileAtl.getAbsolutePath();
        	if (!fileAsm.exists())
        		AtlCompiler.getDefault().compile(new File(absAtlPath).toURI().toURL().openStream(),absPath);
        	transformationPath = pathAsm;
        }
        return transformationPath;
	}
	
	/**************** Modifications End ****************/
	/***************************************************/
	
	
	
	/**
	 * The cached value of the '{@link #getInParams() <em>In Params</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getInParams()
	 * @generated
	 * @ordered
	 */
	protected EList<InputActualParameter> inParams;

	/**
	 * The cached value of the '{@link #getOutParams() <em>Out Params</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getOutParams()
	 * @generated
	 * @ordered
	 */
	protected EList<OutputActualParameter> outParams;

	/**
	 * The cached value of the '{@link #getControlNode() <em>Control Node</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getControlNode()
	 * @generated
	 * @ordered
	 */
	protected DecisionNode controlNode;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected TransformationImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return WiresPackage.Literals.TRANSFORMATION;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<InputActualParameter> getInParams() {
		if (inParams == null) {
			inParams = new EObjectContainmentEList<InputActualParameter>(InputActualParameter.class, this, WiresPackage.TRANSFORMATION__IN_PARAMS);
		}
		return inParams;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<OutputActualParameter> getOutParams() {
		if (outParams == null) {
			outParams = new EObjectContainmentEList<OutputActualParameter>(OutputActualParameter.class, this, WiresPackage.TRANSFORMATION__OUT_PARAMS);
		}
		return outParams;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public DecisionNode getControlNode() {
		if (controlNode != null && controlNode.eIsProxy()) {
			InternalEObject oldControlNode = (InternalEObject)controlNode;
			controlNode = (DecisionNode)eResolveProxy(oldControlNode);
			if (controlNode != oldControlNode) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, WiresPackage.TRANSFORMATION__CONTROL_NODE, oldControlNode, controlNode));
			}
		}
		return controlNode;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public DecisionNode basicGetControlNode() {
		return controlNode;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setControlNode(DecisionNode newControlNode) {
		DecisionNode oldControlNode = controlNode;
		controlNode = newControlNode;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, WiresPackage.TRANSFORMATION__CONTROL_NODE, oldControlNode, controlNode));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
		switch (featureID) {
			case WiresPackage.TRANSFORMATION__IN_PARAMS:
				return ((InternalEList<?>)getInParams()).basicRemove(otherEnd, msgs);
			case WiresPackage.TRANSFORMATION__OUT_PARAMS:
				return ((InternalEList<?>)getOutParams()).basicRemove(otherEnd, msgs);
		}
		return super.eInverseRemove(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
			case WiresPackage.TRANSFORMATION__IN_PARAMS:
				return getInParams();
			case WiresPackage.TRANSFORMATION__OUT_PARAMS:
				return getOutParams();
			case WiresPackage.TRANSFORMATION__CONTROL_NODE:
				if (resolve) return getControlNode();
				return basicGetControlNode();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
			case WiresPackage.TRANSFORMATION__IN_PARAMS:
				getInParams().clear();
				getInParams().addAll((Collection<? extends InputActualParameter>)newValue);
				return;
			case WiresPackage.TRANSFORMATION__OUT_PARAMS:
				getOutParams().clear();
				getOutParams().addAll((Collection<? extends OutputActualParameter>)newValue);
				return;
			case WiresPackage.TRANSFORMATION__CONTROL_NODE:
				setControlNode((DecisionNode)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
			case WiresPackage.TRANSFORMATION__IN_PARAMS:
				getInParams().clear();
				return;
			case WiresPackage.TRANSFORMATION__OUT_PARAMS:
				getOutParams().clear();
				return;
			case WiresPackage.TRANSFORMATION__CONTROL_NODE:
				setControlNode((DecisionNode)null);
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
			case WiresPackage.TRANSFORMATION__IN_PARAMS:
				return inParams != null && !inParams.isEmpty();
			case WiresPackage.TRANSFORMATION__OUT_PARAMS:
				return outParams != null && !outParams.isEmpty();
			case WiresPackage.TRANSFORMATION__CONTROL_NODE:
				return controlNode != null;
		}
		return super.eIsSet(featureID);
	}

} //TransformationImpl
